home *** CD-ROM | disk | FTP | other *** search
/ Windows News 2005 February / WN_129_CD.iso / Windows / Extensions Firefox / FlashGot / flashgot-0.5.3.xpi / chrome / flashgot.jar / content / flashgot / flashgotGalleryBuilder.js < prev    next >
Encoding:
JavaScript  |  2004-11-14  |  16.8 KB  |  592 lines

  1. /***** BEGIN LICENSE BLOCK *****
  2.    - Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3.    -
  4.    - The contents of this file are subject to the Mozilla Public License Version
  5.    - 1.1 (the "License"); you may not use this file except in compliance with
  6.    - the License. You may obtain a copy of the License at
  7.    - http://www.mozilla.org/MPL/
  8.    -
  9.    - Software distributed under the License is distributed on an "AS IS" basis,
  10.    - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11.    - for the specific language governing rights and limitations under the
  12.    - License.
  13.    -
  14.    - The Original Code is "FlashGot".
  15.    -
  16.    - The Initial Developer of the Original Code is Giorgio Maone.
  17.    - Portions created by the Initial Developer are Copyright (C) 2004
  18.    - the Initial Developer. All Rights Reserved.
  19.    -
  20.    - Contributor(s): Giorgio Maone <g.maone @ informaction.com>
  21.    -
  22.    - Alternatively, the contents of this file may be used under the terms of
  23.    - either the GNU General Public License Version 2 or later (the "GPL"), or
  24.    - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  25.    - in which case the provisions of the GPL or the LGPL are applicable instead
  26.    - of those above. If you wish to allow use of your version of this file only
  27.    - under the terms of either the GPL or the LGPL, and not to allow others to
  28.    - use your version of this file under the terms of the MPL, indicate your
  29.    - decision by deleting the provisions above and replace them with the notice
  30.    - and other provisions required by the LGPL or the GPL. If you do not delete
  31.    - the provisions above, a recipient may use your version of this file under
  32.    - the terms of any one of the MPL, the GPL or the LGPL.
  33.    -
  34.    - ***** END LICENSE BLOCK *****/
  35.  
  36.  
  37.  
  38. function FlashGotGalleryBuilder() {
  39.   this.expressions={};
  40. }
  41.  
  42. FlashGotGalleryBuilder.INTERVAL_RX=/\[\s*(\d+)\s*-\s*(\d+)\s*(;{0,1}\s*\d*)\s*\]/;
  43. FlashGotGalleryBuilder.INTERVAL_AZ_RX=/\[\s*([a-z]{1})\s*-\s*([a-z]{1})\s*(;{0,1}\s*\d*)\s*\]/i;
  44. FlashGotGalleryBuilder.EXPR_RX=/\[\s*([\w]+)\s*\((.*?)\)\s*\]/i;
  45.  
  46. FlashGotGalleryBuilder.prototype = {
  47.   log: function(msg) {
  48.     window.dump("<FLASHGOT_GB>\n"+msg+"\n</FLASHGOT_GB>\n");
  49.   }
  50. ,
  51.   onload: function() {
  52.     try {
  53.       var data=window.arguments[0];
  54.       this.previewTextBox.value=data.previewURL;
  55.       this.contentTextBox.value=data.contentURL;
  56.       this.referrerTextBox.value=data.referrerURL;
  57.       this.originalWindow=data.originalWindow;
  58.       this.tmpDir=data.tmpDir;
  59.       this.filePath=null;
  60.       this.expressions=data.srcDocument._flashgotGB_expressions;
  61.       if(!this.expressions) this.expressions={};
  62.       this.normalizeURL(this.previewTextBox);
  63.       this.normalizeURL(this.contentTextBox);
  64.       this.validateURLs();
  65.       this.dialog.centerWindowOnScreen();
  66.     } catch(e) {
  67.       this.dialog.cancelDialog();
  68.     }
  69.   }
  70. ,
  71.   get dialog() {
  72.     return document.documentElement;
  73.   }
  74. ,
  75.   get previewBase() {
  76.     return this.trim(this.previewTextBox.value);
  77.   }
  78. , get contentBase() {
  79.     return this.trim(this.contentTextBox.value);
  80.   }
  81. , get referrer() {
  82.     return this.trim(this.referrerTextBox.value);
  83.   }
  84. ,
  85.   get previewTextBox() {
  86.     return document.getElementById("flashgotGB-preview-text");
  87.   }
  88. ,  
  89.   get contentTextBox() {
  90.     return document.getElementById("flashgotGB-content-text");
  91.   }
  92. ,
  93.   get referrerTextBox() {
  94.     return document.getElementById("flashgotGB-referrer-text");
  95.   }
  96.   get urlsListBox() {
  97.     return document.getElementById("flashgotGB-urls-list");
  98.   }
  99. ,  
  100.   get urlsPreviewDoc() {
  101.     return document.getElementById("flashgotGB-urls-preview").contentWindow.document;
  102.   }
  103. ,
  104.   get exprListBox() { 
  105.     return document.getElementById("flashgotGB-expr-list");
  106.   }
  107. ,
  108.   get exprTextBox() {
  109.     return document.getElementById("flashgotGB-expr-text");
  110.   }
  111. ,
  112.   trim: function(s) {
  113.     return s.replace(/^\s+/g,"").replace(/\s+$/g,"");
  114.   }
  115.   checkIntervals: function(url) {
  116.     return url.search(FlashGotGalleryBuilder.INTERVAL_RX)>-1
  117.       || url.search(FlashGotGalleryBuilder.INTERVAL_AZ_RX)>-1
  118.       ;
  119.   }
  120. ,
  121.   normalizeURL: function(textBox) { 
  122.     var url=textBox.value;
  123.     var hasIntervals=this.checkIntervals(url);
  124.     if(!hasIntervals) {
  125.       url=url.replace(/(\{|\(|<)/g,"[").replace(/(\}|\)|>)/g,"]");
  126.       textBox.value=this.checkIntervals(url)
  127.         ?url
  128.         :textBox.value.replace(/(\d+)/g,"[$1-$1;1]");
  129.       }
  130.   }
  131. ,  
  132.   validateURLs: function() {
  133.     var htmlBuilder=new FlashGotGalleryHTML(this);
  134.    
  135.     var oldListBox=this.urlsListBox;
  136.     var container=oldListBox.parentNode;
  137.     
  138.     var listBox=document.createElement("listbox");
  139.     var listCols=document.getElementsByTagName("listcols")[0];
  140.     if(listCols) {
  141.       oldListBox.removeChild(listCols);
  142.       listBox.appendChild(listCols);
  143.     }
  144.     var attrs=oldListBox.attributes;
  145.     for(var j=attrs.length; j-->0;) {
  146.        var attr=attrs[j];
  147.        listBox.setAttribute(attr.nodeName,attr.nodeValue);
  148.     }
  149.     
  150.     container.removeChild(oldListBox);
  151.     container.appendChild(listBox);
  152.     
  153.     htmlBuilder.buildDOM(this.urlsPreviewDoc);
  154.     
  155.     var valid = htmlBuilder.valid;
  156.     
  157.     this.dialog.getButton("accept").setAttribute("disabled",!valid);
  158.     
  159.     if(valid) {
  160.       function createCell(label) {
  161.         var cell=document.createElement('listcell');
  162.         cell.setAttribute("crop","start");
  163.         cell.setAttribute("flex","1");
  164.         cell.setAttribute('label', label?label:"???");
  165.         return cell;
  166.       }
  167.       
  168.       for(var html; html=htmlBuilder.nextFragment();) {
  169.         var item=document.createElement("listitem");
  170.         item.value=html;
  171.         item.appendChild(createCell(htmlBuilder.currentPreviewURL));
  172.         item.appendChild(createCell(htmlBuilder.currentContentURL));
  173.         listBox.appendChild(item);
  174.       }
  175.     }
  176.     
  177.     var exprListBox=this.exprListBox;
  178.     var selectedExpr=exprListBox.selectedItem?exprListBox.selectedItem.label:null;
  179.     while(exprListBox.getRowCount()>0) exprListBox.removeItemAt(0);
  180.     var exprNames=htmlBuilder.exprNames;
  181.     var selectedItem=null;
  182.     for(var j=0, len=exprNames.length; j<len; j++) {
  183.       var item=exprListBox.appendItem(exprNames[j]);
  184.       if(selectedItem==null || item.label==selectedExpr) selectedItem=item;
  185.     }
  186.     if(selectedItem) {
  187.       exprListBox.selectItem(selectedItem);
  188.     }
  189.     this.exprSelected();
  190.     
  191.     
  192.     this.openSelectedURL();
  193.   }
  194. ,
  195.   openSelectedURL: function() {
  196.     var item=this.urlsListBox.selectedItem;
  197.     this.urlsPreviewDoc.getElementById(FlashGotGalleryHTML.prototype.galleryId).innerHTML =
  198.       item?item.value:"";
  199.   }
  200. ,
  201.   synchronizePreview: function() {
  202.     this.synchronizeIntervals(this.contentTextBox,this.previewTextBox);
  203.   }
  204. ,
  205.   synchronizeContent: function() {
  206.     this.synchronizeIntervals(this.previewTextBox,this.contentTextBox);
  207.   }
  208. ,
  209.   synchronizeIntervals: function(srcBox,dstBox) {
  210.     var isrc=new FlashGotGalleryIterator(this.trim(srcBox.value));
  211.     var idst=new FlashGotGalleryIterator(this.trim(dstBox.value));
  212.     var src=""
  213.     var dst=""
  214.     while(isrc && idst && isrc.valid && idst.valid) {
  215.       dst=dst.concat(
  216.           idst.base.substring(0,idst.match.index)
  217.         ).concat(
  218.           isrc.match[0]
  219.         );
  220.        isrc=isrc.delegate;
  221.        idst=idst.delegate;
  222.     }
  223.     if(idst) dst=dst.concat(idst.base);
  224.     dstBox.value=dst;
  225.     this.validateURLs();
  226.   }
  227. ,
  228.   build: function() {
  229.     var htmlBuilder=new FlashGotGalleryHTML(this);
  230.   
  231.     const cc=Components.classes;
  232.     const ci=Components.interfaces;
  233.    
  234.     const galFile=cc["@mozilla.org/file/local;1"].createInstance(ci.nsILocalFile);
  235.     galFile.initWithPath(this.tmpDir.path);
  236.     galFile.append("flashgotGB.html");
  237.     galFile.createUnique(0,-1);
  238.     
  239.     this.filePath=galFile.path;
  240.     
  241.     const os=cc["@mozilla.org/network/file-output-stream;1"].createInstance(
  242.       ci.nsIFileOutputStream);
  243.     
  244.     try {
  245.       os.init(galFile,0x02,-1,0);
  246.       
  247.       var html=htmlBuilder.header; 
  248.       os.write(html,html.length);
  249.       
  250.       while(html=htmlBuilder.nextFragment() ) {
  251.         os.write(html,html.length);
  252.         if(!htmlBuilder.valid) break;
  253.       }
  254.       
  255.       html=htmlBuilder.footer;
  256.       os.write(html,html.length);
  257.     
  258.     } finally {
  259.       os.close();
  260.     }
  261.     const ios=cc['@mozilla.org/network/io-service;1'].getService(ci.nsIIOService);
  262.     
  263.     var w=this.originalWindow;
  264.     var url=ios.newFileURI(galFile).spec;
  265.     if(w.closed) {
  266.       w=window.open(url,"_blank");
  267.     } else {
  268.       var browser=w.getBrowser();
  269.       browser.selectedTab=browser.addTab(url, null);    
  270.     }
  271.   }
  272. ,
  273.   expr2Func: function(expr) {
  274.     return new Function(expr);
  275.   }
  276. ,
  277.   func2Expr: function(func) {
  278.     return func.toString().replace(/^\s*function .*\{\n/,"\n").replace(/\n\}\s*$/,"").replace(/\n\s{3}/g,"\n").replace(/^\n/,"");
  279.   }
  280. ,
  281.   tabSelected: function(ev) {
  282.     switch(ev.target.selectedItem.id) {
  283.       case "flashgotGB-url-tab":
  284.         this.exprChanged();
  285.         break;
  286.       case "flashgotGB-expr-tab":
  287.       default:
  288.         this.validateURLs();
  289.         this.exprTextBox.focus();
  290.     }
  291.   }
  292. ,
  293.   exprSelected: function() {
  294.     var exprTextBox=this.exprTextBox;
  295.     var exprDes=document.getElementById("flashgotGB-expr-des");
  296.     var rxFxName=/\bfunction \w+\(/;
  297.     var errorTextBox=document.getElementById("flashgotGB-expr-error-text");
  298.     errorTextBox.value="";
  299.     var selectedItem=this.exprListBox.selectedItem;
  300.     if(!selectedItem) {
  301.       exprTextBox.value="";
  302.       exprDes.value=exprDes.value.replace(rxFxName,"function fx(");
  303.       exprTextBox.setAttribute("disabled",true);
  304.     } else {
  305.       exprTextBox.removeAttribute("disabled");
  306.       
  307.       var exprName=[selectedItem.label];
  308.       var expr=this.expressions[exprName];
  309.       exprDes.value=exprDes.value.replace(rxFxName,"function "+exprName+"(");
  310.       exprTextBox.value="return \"\";";
  311.       
  312.       switch(typeof(expr)) {
  313.         case "function":
  314.           exprTextBox.value=this.func2Expr(expr);
  315.           exprTextBox.style.color="black";
  316.           errorTextBox.value=expr.lastError
  317.             ?expr.lastError.name+"\n"+expr.lastError.message
  318.             :"";
  319.           break;
  320.         case "string":
  321.           exprTextBox.value=expr;
  322.         default:
  323.           exprTextBox.style.color="red";
  324.       }
  325.     }
  326.   }
  327.   exprChanged: function() {
  328.     var selectedItem=this.exprListBox.selectedItem;
  329.     if(!selectedItem) {
  330.       this.exprTextBox.setAttribute("disabled",true);
  331.     } else {
  332.       this.exprTextBox.removeAttribute("disabled");
  333.       var expr=this.exprTextBox.value;
  334.       try {
  335.         expr=this.expr2Func(expr);
  336.       } catch(e) {
  337.         this.exprTextBox.focus();
  338.         document.getElementById("flashgotGB-expr-error-text").value=e.message;
  339.       }
  340.       this.expressions[selectedItem.label]=expr;
  341.       this.validateURLs();
  342.     }
  343.   }
  344. }
  345.  
  346.  
  347. function FlashGotGalleryHTML(builder) {
  348.   this.builder=builder;
  349.   this.previews=new FlashGotGalleryIterator(builder.previewBase);
  350.   this.contents=new FlashGotGalleryIterator(builder.contentBase);
  351.   var exprNames=[];
  352.   for(var base=builder.previewBase.concat(builder.contentBase), match=null;
  353.     match=base.match(FlashGotGalleryBuilder.EXPR_RX);
  354.     base=base.substring(match.index+match[0].length)
  355.     ) {
  356.       var name=match[1];
  357.       for(var j=exprNames.length; j-->0 && exprNames[j]!=name;);
  358.       if(j<0) exprNames[exprNames.length]=name;
  359.   }
  360.   this.exprNames=exprNames.sort();
  361.   this.index=0;
  362. }
  363.  
  364.  
  365.  
  366. FlashGotGalleryHTML.prototype = {
  367.   
  368.   galleryId: "flashgotGB-gallery"
  369. ,
  370.   get headElementSource() {
  371.     function jsEscape(s) {
  372.       return (s==null
  373.           ?"null"
  374.           :'"'+s.replace(/([\\"\n\t])/g,"\\$1")+'"'
  375.           );
  376.     }
  377.     
  378.     function jsvar(n,s) {
  379.       return 'document.'+n+'='
  380.         + jsEscape(s) +';';
  381.     }
  382.     
  383.     function serializeExpressions(exprNames,expressions) {
  384.       var code="document._flashgotGB_expressions={\n";
  385.       var props=new Array();
  386.       for(var j=0, len=exprNames.length; j<len; j++) {
  387.         var n=exprNames[j];
  388.         var v=expressions[n];
  389.         if(v) {
  390.           props[props.length]=n + ": "
  391.             + (typeof(v)=="function"?v.toString():jsEscape(v));
  392.         }
  393.       }
  394.       return code.concat(props.join("\n,\n")).concat("\n};");
  395.     }
  396.     
  397.     return '<head><title>'+this.builder.referrer+" - "
  398.       +this.builder.dialog.getAttribute('title')+'</title>\n'
  399.         +'<script type="text/javascript">'
  400.         + jsvar('_flashgotGB_referrer',this.builder.referrer)
  401.         + jsvar('_flashgotGB_previews',this.previews.base)
  402.         + jsvar('_flashgotGB_contents',this.contents.base)
  403.         + serializeExpressions(this.exprNames,this.builder.expressions)
  404.         +'</script>\n'
  405.         +'<style type="text/css">\n'
  406.         +'body,div { font-family: verdana,arial,hevetica,sans-serif; '
  407.         +'font-size: 10px; color: black; background: white }\n}'
  408.         +'a { color: blue; text-decoration: underline; }\n'
  409.         +'</style></head>'
  410.         ;
  411.   }
  412.   get header() {
  413.      return '<html>'
  414.         +this.headElementSource
  415.         +'<body>\n'
  416.         +'<div id="'+this.galleryId+'">\n'
  417.         ;
  418.   }
  419. ,  
  420.   get footer() {
  421.     return "\n</div></body></html>";
  422.   }
  423. ,
  424.   evalExpressions: function(iterator) {
  425.     var url=iterator.nextURL();
  426.     if( ! ( url &&  this.exprNames.length)  ) return url;
  427.     var base=url;
  428.     var evalURL="";
  429.     var obj = { index: this.index, baseURL: base };
  430.     for(var match=null;
  431.         match=base.match(FlashGotGalleryBuilder.EXPR_RX);
  432.         base=base.substring(match.index+match[0].length)
  433.     ) {
  434.       var name=match[1];
  435.       var expr=this.builder.expressions[name];
  436.       var subst=match[0];
  437.       if(typeof(expr)=="function") {
  438.         try {
  439.           obj.expr=expr;
  440.           var res=eval("obj.expr("+match[2]+")");
  441.           if(res!=null && typeof(res)!="undefined") {
  442.             subst=res;
  443.           }
  444.         } catch(e) {
  445.           expr.lastError=e;
  446.         }
  447.       }
  448.       evalURL+=base.substring(0,match.index).concat(subst);
  449.     }
  450.     evalURL+=base;
  451.     return evalURL;
  452.   }
  453. ,
  454.   nextFragment: function() {
  455.   
  456.      var p = this.currentPreviewURL = 
  457.       this.evalExpressions(this.previews);
  458.      var c = this.currentContentURL = 
  459.       this.evalExpressions(this.contents);
  460.      if( 
  461.        (! (p || c) )
  462.       || (p==null && !this.contents.valid) 
  463.       || (c==null && !this.previews.valid) 
  464.       ) {
  465.         return null;
  466.      }
  467.      
  468.      
  469.      var html=p?'<img src="'+p+'" alt="'+(c?c:"???")+'" />':c+'<br />\n';
  470.      if(c) html='<a href="'+c+'">'+html+'</a>\n';
  471.      return html;
  472.   }
  473. ,  
  474.   get valid() {
  475.     return this.previews.valid || this.contents.valid;
  476.   }
  477. ,  
  478.   reset: function() {
  479.     this.previews.reset();
  480.     this.contents.reset();
  481.     this.index=0;
  482.   }
  483. ,
  484.   buildDOM: function(doc) {
  485.     if(!doc.getElementById(this.galleryId)) {
  486.       doc.documentElement.innerHTML=this.headElementSource;
  487.       doc.documentElement.appendChild(doc.createElement("body")
  488.       ).appendChild(doc.createElement("div")).id=this.galleryId;
  489.     }
  490.   }
  491.  
  492. }
  493.  
  494.  
  495. function FlashGotGalleryIterator(base) {
  496.   this.base=base;
  497.   var match=FlashGotGalleryBuilder.INTERVAL_RX.exec(this.base);
  498.   if(match) {
  499.     this.isAZ=false;
  500.     this.start=parseInt(match[1],10);
  501.     this.end=parseInt(match[2],10);
  502.     this.padding="";
  503.     for(var j=(this.end>this.start?match[1]:match[2]).length; 
  504.       j-->0; 
  505.       this.padding=this.padding.concat("0") 
  506.       );
  507.     this.valid=true;
  508.   } else {
  509.     match=FlashGotGalleryBuilder.INTERVAL_AZ_RX.exec(this.base);
  510.     if(this.isAZ=match!=null) {
  511.       if(/[a-z]{1}/.test(match[1])) {
  512.         match[2]=match[2].toLowerCase();
  513.       } else {
  514.         match[2]=match[2].toUpperCase();
  515.       }
  516.       
  517.       this.start=match[1].charCodeAt(0);
  518.       this.end=match[2].charCodeAt(0);
  519.       
  520.       this.valid=true;
  521.     } else {
  522.       this.valid=false;
  523.       return;
  524.     }
  525.   }
  526.   this.match=match;
  527.   
  528.   var stepMatch=this.match[3].match(/;\s*(\d+)/);
  529.   this.step = 
  530.     (stepMatch?parseInt(stepMatch[1],10):1)
  531.     * 
  532.     (this.start<=this.end?1:-1)
  533.     ;
  534.     
  535.   this.cursor=this.start;
  536.  
  537.   this.delegate=new FlashGotGalleryIterator(
  538.     this.match.input.substring(this.match.index+this.match[0].length)
  539.     );
  540. }
  541.   
  542. FlashGotGalleryIterator.prototype = {
  543.   reset: function() {
  544.     this.cursor=this.start;
  545.     if(this.delegate) this.delegate.reset();
  546.   }
  547. ,
  548.   nextURL: function() {
  549.     if(!this.valid) return this.base;
  550.     
  551.     if(this.step==0
  552.       || (this.step>0 && this.cursor>this.end)
  553.       || (this.step<0 && this.cursor<this.end)) {
  554.       return null;
  555.     }
  556.     
  557.     var count;
  558.     
  559.     if(this.isAZ) {
  560.       count=String.fromCharCode(this.cursor);
  561.     } else {
  562.       count=new String(this.cursor);
  563.       if(count.length<this.padding.length) {
  564.         count=this.padding.substring(count.length).concat(count);
  565.       }
  566.     }
  567.     
  568.     var delegatePart=this.delegate.nextURL();
  569.     if(delegatePart==null || !this.delegate.valid) {
  570.       this.cursor+=this.step;
  571.       if(delegatePart==null) {
  572.         this.delegate.reset();
  573.         return this.nextURL();
  574.       }
  575.     }
  576.     
  577.     return this.match.input.substring(0,this.match.index
  578.       ).concat(count
  579.       ).concat(delegatePart);  
  580.    
  581.   }
  582.  
  583.   
  584. }
  585.  
  586. var flashgotGB=new FlashGotGalleryBuilder();
  587.  
  588.